<template>
  <div class="virtual-group-table">
    <!-- 表头部分 -->
    <div class="table-header disFlx">
      <div class="header-cell serial-col">序号</div>
      <div class="header-cell seat-col">位置编号</div>
      <div class="header-cell name-col">姓名</div>
      <div class="header-cell company-col">单位</div>
      <div class="header-cell position-col">会员职务</div>
      <div class="header-cell sign-col">签到情况</div>
      <div class="header-cell action-col">操作</div>
      <div class="scrollbar-space"></div>
    </div>
    
    <!-- 表格内容部分 - 虚拟滚动区域 -->
    <div class="table-body" ref="tableBody" style="height: 550px; overflow-y: scroll;" @scroll="handleScroll">
      <div class="virtual-list-container" :style="{ height: `${totalHeight}px` }">
        <div class="virtual-list" :style="{ transform: `translateY(${startOffset}px)` }">
          <div 
            v-for="(item, index) in visibleData" 
            :key="item.id + '-' + index + '-' + (item.userId || 0)" 
            class="table-row disFlx"
            :data-index="startIndex + index"
          >
            <!-- 序号列 -->
            <div class="table-cell serial-col fontTC">{{ startIndex + index + 1 }}</div>
            
            <!-- 位置编号列 -->
            <div class="table-cell seat-col">
              <div v-if="item.operability" class="disFlxAC">
                <a-input
                  v-model="item.displayName"
                  @blur="editDisplayName(item)"
                  :id="'displayNameInput' + item.id"
                  class="text-center width-9"
                />
              </div>
              <div v-else class="disFlxAC flexCenter">
                <div>{{ item.displayName }}</div>
                <a-icon v-if="locationRule === 'IMPORT'" class="_p-5 cup" type="edit" @click="_toggle(item)" />
              </div>
            </div>
            
            <!-- 姓名列 -->
            <div class="table-cell name-col">
              <!-- 占位状态 -->
              <template v-if="item.userId === -1">
                <div class="disFlx">
                  <a-tag color="pink" class="cup" @click.stop="deleteUser(item)">取消占位</a-tag>
                  <a-tag color="blue" class="cup" @click.stop="openSelectUserModel(3, item.id)">添加人员</a-tag>
                </div>
              </template>
              <!-- 无人员 -->
              <template v-else-if="!item.userId">
                <div class="disFlx">
                  <a-tag color="green" class="cup" @click.stop="lockSeat(item)">立即占位</a-tag>
                  <a-tag color="blue" class="cup" @click.stop="openSelectUserModel(2, item.id)">添加人员</a-tag>
                </div>
              </template>
              <div v-else class="disFlxAC flexCenter">
                <span class="ov-1">{{ item.userName || '' }}</span>
                <a-tooltip title="移除人员">
                  <a-icon class="_pl-10 linh-20 flexS0" type="close" @click.stop="deleteUser(item)" />
                </a-tooltip>
              </div>
            </div>
            
            <!-- 单位列 -->
            <div class="table-cell company-col">
              <a-tooltip v-if="item.userCompanyName" :title="item.userCompanyName">
                <div class="ov-2">{{ item.userCompanyName }}</div>
              </a-tooltip>
              <div v-else>-</div>
            </div>
            
            <!-- 会员职务列 -->
            <div class="table-cell position-col">
              <a-tooltip v-if="item.userPosition" :title="item.userPosition">
                <div class="ov-2">{{ item.userPosition }}</div>
              </a-tooltip>
              <div v-else>-</div>
            </div>
            
            <!-- 签到情况列 -->
            <div class="table-cell sign-col fontTC">
              <span v-if="item.signStatus">{{ item.signStatus == signStatusEnum.STAY ? '未签到' : '已签到' }}</span>
              <span v-else>-</span>
            </div>
            
            <!-- 操作列 -->
            <div class="table-cell action-col">
              <a-button type="primary" size="small" ghost @click.stop="deleteRow(item, startIndex + index)">
                移除位置
              </a-button>
              <a-button type="primary" size="small" :disabled="!item.userId" ghost @click.stop="openChangePlaceModel(item)">
                换位置
              </a-button>
              <a-button type="primary" size="small" ghost @click.stop="upRow(startIndex + index)">
                上移一行
              </a-button>
              <a-button type="primary" size="small" ghost @click.stop="downRow(startIndex + index)">
                下移一行
              </a-button>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    <!-- 加载中提示 -->
    <div v-if="loading" class="loading-container disFlxCC">
      <a-spin tip="加载中..." />
    </div>
    
    <!-- 添加按钮 -->
    <div class="fontTC _pt-14 _pb-10">
      <a-tag color="blue" class="cup _pl-30 _pr-30 linh-25" @click.stop="addRow()">
        添加
      </a-tag>
    </div>
  </div>
</template>

<script>
import Sortable from 'sortablejs'
import {
  activityArrangeAddSeat,
  activityArrangeDelSeat,
  activityArrangeSwapSeat,
  activityArrangeClear,
  activityArrangeLockSeat,
  activityUpdateSeatName
} from '@/api/activity/activity.js'
import { cloneDeep } from 'lodash-es'
import { signStatusEnum } from '@/enums/activity'

export default {
  name: 'VirtualGroupTable',
  props: {
    tableId: {
      type: Number
    },
    // 位置排座方式 AUTO 自动生成 IMPORT 导入
    locationRule: {
      type: String,
      default: 'AUTO'
    },
    tableData: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      loading: false,
      oldDisplayName: undefined,
      signStatusEnum,
      
      // 虚拟滚动相关
      rowHeight: 50, // 每行高度，必须与CSS中的.table-row的height保持一致
      bufferSize: 5, // 缓冲区大小
      startIndex: 0, // 开始索引
      endIndex: 0, // 结束索引
      startOffset: 0, // 开始偏移量
      visibleCount: 0, // 可见数量
      sortableInstance: null // 用于存储sortable实例
    }
  },
  computed: {
    // 总高度
    totalHeight() {
      return this.tableData.length * this.rowHeight
    },
    // 可见数据
    visibleData() {
      return this.tableData.slice(this.startIndex, this.endIndex + 1)
    }
  },
  watch: {
    tableData: {
      handler() {
        this.$nextTick(() => {
          this.updateVisibleRange()
          this.initSortable()
        })
      },
      deep: true
    }
  },
  mounted() {
    this.updateVisibleRange()
    this.$nextTick(() => {
      this.initSortable()
    })
    
    // 监听窗口大小变化
    window.addEventListener('resize', this.updateVisibleRange)
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.updateVisibleRange)
    // 销毁sortable实例
    if (this.sortableInstance) {
      this.sortableInstance.destroy()
      this.sortableInstance = null
    }
  },
  methods: {
    // 滚动处理
    handleScroll() {
      this.updateVisibleRange()
    },
    
    // 更新可见范围
    updateVisibleRange() {
      const { tableBody } = this.$refs
      if (!tableBody) return
      
      // 计算可见区域的开始索引和结束索引
      const scrollTop = tableBody.scrollTop
      const clientHeight = tableBody.clientHeight
      
      // 计算开始索引和偏移量
      this.startIndex = Math.floor(scrollTop / this.rowHeight)
      this.startIndex = Math.max(0, this.startIndex - this.bufferSize)
      
      // 计算结束索引
      this.visibleCount = Math.ceil(clientHeight / this.rowHeight) + 2 * this.bufferSize
      this.endIndex = Math.min(this.tableData.length - 1, this.startIndex + this.visibleCount)
      
      // 计算偏移量
      this.startOffset = this.startIndex * this.rowHeight
    },
    
    // 滚动到指定索引
    scrollToIndex(index) {
      const { tableBody } = this.$refs
      if (!tableBody) return
      
      tableBody.scrollTop = index * this.rowHeight
    },
    
    // 滚动到底部
    scrollToBottom() {
      const { tableBody } = this.$refs
      if (!tableBody) return
      
      tableBody.scrollTop = this.totalHeight
    },
    
    _toggle(row) {
      this.oldDisplayName = row.displayName
      this.$set(row, 'operability', true)
      this.$nextTick(() => {
        const tbList = this.$el.querySelector(`#displayNameInput${row.id}`)
        if (tbList) {
          tbList.focus() // 输入框自动聚焦
        }
      })
    },
    
    // 修改位置编号
    editDisplayName(row) {
      row.operability = false
      if (row.displayName === this.oldDisplayName) return
      activityUpdateSeatName({ id: row.id, name: row.displayName })
    },
    
    openChangePlaceModel(data) {
      this.$emit('openChangePlaceModel', data)
    },
    
    // 选择人员 type 1: 批量选择人员 2.指定座位添加人员 3.指定座位添加人员(座位为占座)
    openSelectUserModel(type, seatId) {
      this.$emit('openSelectUserModel', type, this.tableId, seatId)
    },
    
    // 删除一行 -前端静默更新
    deleteRow(row, index) {
      this.loading = true
      activityArrangeDelSeat({ seatId: row.id }).then(() => {
        this.tableData.splice(index, 1)
        this.$emit('resetHead') // 刷新头部信息
        this.updateVisibleRange()
        this.loading = false
      }).catch(() => {
        this.loading = false
      })
    },
    
    // 清空位置,移除人员 -前端静默更新
    deleteUser(row) {
      this.loading = true
      activityArrangeClear({ seatId: row.id }).then(() => {
        row.userId = null
        row.userName = null
        row.userPosition = null
        row.userCompanyName = null
        this.$emit('resetHead') // 刷新头部信息
        this.loading = false
      }).catch(() => {
        this.loading = false
      })
    },
    
    // 占位 -前端静默更新
    lockSeat(row) {
      this.loading = true
      activityArrangeLockSeat({ seatId: row.id }).then(() => {
        row.userId = -1
        this.$emit('resetHead') // 刷新头部信息
        this.loading = false
      }).catch(() => {
        this.loading = false
      })
    },
    
    // 增加一行 -根据后端返回静默更新
    addRow() {
      this.loading = true
      activityArrangeAddSeat({ groupId: this.tableId }).then(res => {
        this.tableData.push(res.data)
        this.$nextTick(() => {
          this.scrollToBottom()
        })
        this.$emit('resetHead') // 刷新头部信息
        this.loading = false
      }).catch(() => {
        this.loading = false
      })
    },
    
    // 上移一行 -前端静默更新
    upRow(index) {
      if (index === 0) return
      
      this.loading = true
      this._sortFn(index, index - 1)
    },
    
    // 下移一行 -前端静默更新
    downRow(index) {
      if (index + 1 >= this.tableData.length) return
      
      this.loading = true
      this._sortFn(index, index + 1)
    },
    
    // 初始化拖拽
    initSortable() {
      const _this = this
      const virtualList = this.$el.querySelector('.virtual-list')
      
      if (!virtualList) return
      
      // 销毁之前的实例（如果有）
      if (this.sortableInstance) {
        this.sortableInstance.destroy()
      }
      
      this.sortableInstance = new Sortable(virtualList, {
        handle: '.table-row',
        animation: 150,
        ghostClass: 'blue-background-class', // 拖拽时的影子元素样式
        chosenClass: 'dragging',            // 被选中行的样式
        onEnd: function(evt) {
          const oldIndex = parseInt(evt.item.dataset.index, 10)
          // 正确计算新位置索引，需要使用evt.newDraggableIndex来获取相对于整个列表的新位置
          let newIndex = _this.startIndex + parseInt(evt.newIndex, 10)
          
          // 确保索引在有效范围内
          if (oldIndex === newIndex || newIndex >= _this.tableData.length) return
          _this._sortFn(oldIndex, newIndex)
        }
      })
    },
    
    // 表格排序
    _sortFn(oldIndex, newIndex) {
      this.loading = true
      const oldRow = cloneDeep(this.tableData[oldIndex])
      const newRow = cloneDeep(this.tableData[newIndex])
      
      if (!oldRow.userId && !newRow.userId) {
        // 都无人员,拦截不调用接口
        this.loading = false
        return
      }
      
      // 先在前端更新
      this.tableData[oldIndex].userId = newRow.userId
      this.tableData[oldIndex].userName = newRow.userName
      this.tableData[oldIndex].userPosition = newRow.userPosition
      this.tableData[oldIndex].userCompanyName = newRow.userCompanyName
      this.tableData[oldIndex].signStatus = newRow.signStatus
      
      this.tableData[newIndex].userId = oldRow.userId
      this.tableData[newIndex].userName = oldRow.userName
      this.tableData[newIndex].userPosition = oldRow.userPosition
      this.tableData[newIndex].userCompanyName = oldRow.userCompanyName
      this.tableData[newIndex].signStatus = oldRow.signStatus
      
      // 后端更新
      activityArrangeSwapSeat({ seatId: oldRow.id, targetSeatId: newRow.id }).then(() => {
        this.loading = false
      }).catch(() => {
        // 更新失败，恢复原状态
        this.tableData[oldIndex] = oldRow
        this.tableData[newIndex] = newRow
        this.loading = false
      })
    }
  }
}
</script>

<style lang="less" scoped>
.virtual-group-table {
  position: relative;
  width: 100%;
  border: 1px solid #e8e8e8;
  
  .table-header {
    background-color: #fafafa;
    border-bottom: 1px solid #e8e8e8;
    font-weight: 500;
    padding-right: 16px; // 为滚动条预留空间
  }
  
  .header-cell {
    padding: 12px 6px;
    font-weight: bold;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    text-align: center;
  }
  
  .table-body {
    position: relative;
  }
  
  .virtual-list-container {
    position: relative;
  }
  
  .virtual-list {
    position: absolute;
    width: 100%;
  }
  
  .table-row {
    border-bottom: 1px solid #e8e8e8;
    cursor: pointer;
    height: 50px; // 固定行高，确保虚拟滚动计算准确
    
    &:hover {
      background-color: #f5f5f5;
    }
    
    &.dragging {
      background-color: #e6f7ff;
    }
  }
  
  .table-cell {
    padding: 0 6px;
    overflow: hidden;
    text-overflow: ellipsis;
    height: 100%; // 使单元格高度与行一致
    display: flex;
    align-items: center;
  }
  
  .serial-col {
    width: 60px;
    flex-shrink: 0;
    justify-content: center;
  }
  
  .seat-col {
    width: 120px;
    flex-shrink: 0;
    justify-content: center;
  }
  
  .name-col {
    min-width: 150px;
    flex-shrink: 0;
    justify-content: center;
  }
  
  .company-col {
    flex: 1;
    min-width: 120px;
    justify-content: center;
  }
  
  .position-col {
    flex: 1;
    min-width: 120px;
    justify-content: center;
  }
  
  .sign-col {
    width: 100px;
    flex-shrink: 0;
    justify-content: center;
  }
  
  .action-col {
    width: 300px; // 调整宽度适应四个按钮
    flex-shrink: 0;
    gap: 4px; // 缩小间距
  }
  
  .loading-container {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(255, 255, 255, 0.7);
    z-index: 10;
  }
  
  // 蓝色背景类，用于拖拽时的影子元素效果
  .blue-background-class {
    background-color: rgba(230, 247, 255, 0.5) !important;
    border: 1px dashed #1890ff !important;
  }
}

// 额外添加的工具类
.text-center {
  text-align: center;
}
</style> 